package com.micro.glszh.stat.exception.handler;

import com.micro.glszh.stat.base.CommonResult;
import com.micro.glszh.stat.base.HttpCodeEnum;
import com.micro.glszh.stat.exception.BusinessException;
import com.micro.glszh.stat.exception.BadRequestException;
import com.micro.glszh.stat.exception.EntityExistException;
import com.micro.glszh.stat.exception.WxAccessTokenException;
import com.micro.glszh.stat.exception.WxMessageSendException;
import com.micro.glszh.stat.utils.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;

import java.util.List;

/**
 * @author yaochenglong
 * @version 1.0
 * @description: 全局异常处理
 * @date 2023/3/7 10:37
 */
@Order(101)
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {


    @Value("${spring.servlet.multipart.max-request-size:4M}")
    private String maxRequestSize;

    @Value("${spring.servlet.multipart.max-file-size:100M}")
    private String maxFileSize;

    @ExceptionHandler(value = BadRequestException.class)
    public CommonResult<Object> badRequestException(BadRequestException e) {
        log.error(e.getMessage());
        log.error(e.getCode().toString());
        return CommonResult.failed(e.getCode(), e.getMessage());
    }

    /**
     * 业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    public CommonResult<Object> businessException(BusinessException e) {
        log.error(e.getMessage());
        return CommonResult.failed(e.getMessage());
    }

    @ExceptionHandler(value = EntityExistException.class)
    public CommonResult<Object> entityExistException(EntityExistException e) {
        // 打印堆栈信息
        log.error(ThrowableUtil.getStackTrace(e));
        return CommonResult.failed(e.getMessage());
    }

    /**
     * 小程序推送消息异常
     *
     * @param e
     */
    @ExceptionHandler(value = WxMessageSendException.class)
    public CommonResult<Object> wxMessageSendException(WxMessageSendException e) {
        log.error(e.getMessage());
        return CommonResult.failed(e.getMessage());
    }

    /**
     * 获取微信授权异常
     *
     * @param e
     */
    @ExceptionHandler(value = WxAccessTokenException.class)
    public CommonResult<Object> wxAccessTokenException(WxAccessTokenException e) {
        log.error(e.getMessage());
        return CommonResult.failed(e.getMessage());
    }

    /**
     * 处理空指针的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    public CommonResult<Object> exceptionHandler(NullPointerException e) {
        log.error("发生空指针异常！原因是:", e);
        return CommonResult.failed(HttpCodeEnum.INVALID_REQUEST, e.getMessage());
    }

    @ExceptionHandler(value = MultipartException.class)
    public CommonResult<Object> sizeException(MaxUploadSizeExceededException e) {
        log.error("上传文件异常！原因是:", e);
        return CommonResult.failed(HttpCodeEnum.SIZE_LIMIT_EXCEEDED_EXCEPTION, String.format("单个文件不超过%s,总大小不超过%s", maxRequestSize, maxFileSize));
    }

    /**
     * 数组越界异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = ArrayIndexOutOfBoundsException.class)
    public CommonResult<String> arrayIndexOutOfHandler(ArrayIndexOutOfBoundsException e) {
        log.error("发生数组越界异常！原因是:", e);
        return CommonResult.failed(HttpCodeEnum.BODY_NOT_MATCH);
    }

    /**
     * 兼容Validation校验框架：忽略参数异常处理器
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public CommonResult<String> parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
        log.error(e.getMessage(), e);
        return CommonResult.failed(HttpCodeEnum.INVALID_REQUEST, "请求参数 " + e.getParameterName() + " 不能为空");
    }

    /**
     * 兼容Validation校验框架：缺少请求体异常处理器
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public CommonResult<String> parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
        log.error(e.getMessage(), e);
        return CommonResult.failed(HttpCodeEnum.INVALID_REQUEST, "参数体不能为空");
    }

    /**
     * 兼容Validation校验框架：参数效验异常处理器
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResult<String> parameterExceptionHandler(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        // 获取异常信息
        BindingResult exceptions = e.getBindingResult();
        // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                return CommonResult.failed(HttpCodeEnum.INVALID_REQUEST, fieldError.getDefaultMessage());
            }
        }
        return CommonResult.failed(HttpCodeEnum.INVALID_REQUEST, "请求参数校验异常");
    }

}
